Project 1 - 自我介紹程式(5):衍伸變化並複習前幾天的內容 - 實作多語系與跨視窗應用
https://ithelp.ithome.com.tw/articles/10214008
1.多語系檔案 - 專案是每個程式作品的單位:
2.選擇語系 - 讓程式在對的時間點完成一件事:
讀寫檔跟多語系一樣,是許多資訊系統當中常見的功能需求。然而實作讀寫檔的過程非常容易造成程式的錯誤。包括資料夾或檔案不存在、資料為Null或空值、型態的錯誤。面對這些錯誤對學習者和教學者造成無數的挫折感和時間的耗費
當我輸入個人資訊、選擇大頭貼,按下保存之後,將這些資訊存到檔案當中:
存檔之後,在程式的檔案附近看到被保存的JSON資料和圖片檔:
個人資料在JSON的資料格式:
可以實作的檔案類型包括「TXT、CSV、JSON、XML、XLS」,每一種檔案格式都有對應的IO函式庫。今天我們將使用Json.net函式庫,以JSON來實作檔案讀寫
在C#,可以使用Image函式庫來處理圖片,或者透過Stream 讀取Byte[]後轉成陣列
讀取檔案結果檔案不存在
讀取檔案資料,結果因為檔案裡面的資料結構有問題,無法存到變數當中
將資料寫入檔案,結果資料夾或檔案路徑不存在
將資料寫入檔案,結果資料為NULL,寫入文字檔的過程中無法轉成文字造成錯誤。寫入圖片檔的過程中無法轉成圖片格式造成錯誤
1.確認資料夾與檔案是否存在
// 如果資校夾不存在
if (!Directory.Exists(dirPath))
{
}
// 如果檔案不存在
if (!File.Exists(jsonPath))
{
}
(1) 建立資料夾與檔案
// 建立資料夾
Directory.CreateDirectory(dirPath);
// 建立檔案
File.Create(jsonPath).Close();
(2) 讀檔
// 從JSON檔讀取先前保存的個人資訊
string introductionJsonStr = File.ReadAllText(filePath);
photoBox.Image = Image.FromFile(imagePath);
(3) 寫檔
// 保存個人資訊到JSON
File.WriteAllText(jsonPath, JsonConvert.SerializeObject(introductionJson));
// 保存個人大頭貼到Jpeg 圖片
photoBox.Image.Save(imagePath, ImageFormat.Jpeg);
3.進行讀檔後、寫檔前,確認資料結構是否正常
JObject introductionJson = (JObject)JsonConvert.DeserializeObject(introductionJsonStr);
//讀完資料發現資料空白、結構有缺漏、結構被破壞,不要讀取
if (introductionJson == null ||
!introductionJson.ContainsKey("Name") || !introductionJson.ContainsKey("HomeTown") || !introductionJson.ContainsKey("BirthDate"))
{
return;
}
else
{
nameTextBox.Text = introductionJson["Name"].ToString();
homeTownTextBox.Text = introductionJson["HomeTown"].ToString();
birthdate_YearBox.Text = introductionJson["BirthDate"].ToString().Split('-')[0];
birthdate_MonthBox.Text = introductionJson["BirthDate"].ToString().Split('-')[1];
birthdate_DayBox.Text = introductionJson["BirthDate"].ToString().Split('-')[2];
}
1.將Json.net函式庫,透過Nuget安裝到專案當中
2.當自我介紹主畫面開啟時(Load事件),進行讀檔
// IntroductionForm.cs
private void IntroductionForm_Load(object sender, EventArgs e)
{
loadSaveIntroduction();
MessageBox.Show(LanguageResources.FormStart);
}
/// <summary>
/// 將自我介紹的資訊顯示到畫面上
/// </summary>
private void loadSaveIntroduction()
{
string dirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data");
string filePath = Path.Combine(dirPath, "Introduction.json");
string imagePath = Path.Combine(dirPath, "Photo.jpeg");
// 每次讀寫檔之前,檢查路徑的資料夾與檔案是否存在,避免發生路徑不存在的錯誤
if (!Directory.Exists(dirPath) || !File.Exists(filePath) || !File.Exists(imagePath))
{
return;
}
// 從JSON檔讀取先前保存的個人資訊
string introductionJsonStr = File.ReadAllText(filePath);
JObject introductionJson = (JObject)JsonConvert.DeserializeObject(introductionJsonStr);
//讀完資料發現資料空白、結構有缺漏、結構被破壞,不要讀取
if (introductionJson == null ||
!introductionJson.ContainsKey("Name") || !introductionJson.ContainsKey("HomeTown") || !introductionJson.ContainsKey("BirthDate"))
{
return;
}
else
{
nameTextBox.Text = introductionJson["Name"].ToString();
homeTownTextBox.Text = introductionJson["HomeTown"].ToString();
birthdate_YearBox.Text = introductionJson["BirthDate"].ToString().Split('-')[0];
birthdate_MonthBox.Text = introductionJson["BirthDate"].ToString().Split('-')[1];
birthdate_DayBox.Text = introductionJson["BirthDate"].ToString().Split('-')[2];
}
photoBox.Image = Image.FromFile(imagePath);
}
3.當使用者按下,「保存個人資訊」時,將資料寫入JSON與圖片檔
// IntroductionForm.cs
/// <summary>
/// 按下「保存個人資訊」
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void saveBtn_Click(object sender, EventArgs e)
{
// 校驗每個欄位是否輸入
TextBox[] allTextBox = new TextBox[] { nameTextBox, homeTownTextBox, birthdate_YearBox, birthdate_MonthBox, birthdate_DayBox };
string[] allTextBoxName = new string[]{LanguageResources.Name, LanguageResources.HomeTown,
LanguageResources.Birthday_Year, LanguageResources.Birthday_Month, LanguageResources.Birthday_Day };
StringBuilder errorMsg = new StringBuilder();
for (int i = 0; i < allTextBox.GetLength(0); i++)
{
if (string.IsNullOrEmpty(allTextBox[i].Text))
{
errorMsg.AppendLine(string.Format(LanguageResources.Message_PleaseInput, allTextBoxName[i]));
}
}
if (errorMsg.ToString() != "")
{
MessageBox.Show(errorMsg.ToString(), "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 校驗日期格式是否正確
if (!Regex.IsMatch(birthdate_YearBox.Text, @"\d") || !Regex.IsMatch(birthdate_MonthBox.Text, @"\d") || !Regex.IsMatch(birthdate_DayBox.Text, @"\d"))
{
MessageBox.Show(LanguageResources.Message_BirthdayNeedNum, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 檢查有沒有選擇大頭照
if (photoBox.Image == null)
{
MessageBox.Show(LanguageResources.Message_NoImage, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string name = nameTextBox.Text;
string homeTown = homeTownTextBox.Text;
int birthDate_Year = int.Parse(birthdate_YearBox.Text);
int birthDate_Month = int.Parse(birthdate_MonthBox.Text);
int birthDate_Day = int.Parse(birthdate_DayBox.Text);
JObject introductionJson = new JObject();
introductionJson.Add("Name", name);
introductionJson.Add("HomeTown", homeTown);
introductionJson.Add("BirthDate", string.Format("{0}-{1}-{2}", birthDate_Year, birthDate_Month, birthDate_Day));
string dirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data");
string jsonPath = Path.Combine(dirPath, "Introduction.json");
string imagePath = Path.Combine(dirPath, "Photo.jpeg");
// 每次讀寫檔之前,檢查路徑的資料夾與檔案是否存在,避免發生路徑不存在的錯誤
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
// 檔案不存在,產生個人資訊的檔案
if (!File.Exists(jsonPath))
{
File.Create(jsonPath).Close();
}
// 保存個人資訊到JSON
File.WriteAllText(jsonPath, JsonConvert.SerializeObject(introductionJson));
// 保存個人大頭貼到Jpeg 圖片
photoBox.Image.Save(imagePath, ImageFormat.Jpeg);
MessageBox.Show("保存完成!", "訊息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
using System;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
namespace IT_Day01
{
public partial class IntroductionForm : Form
{
public IntroductionForm(int languageIndex)
{
string[] language = { "zh-TW", "en-US" };
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language[languageIndex]);
InitializeComponent();
}
/// <summary>
/// 顯示邀請自我介紹的文字
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void IntroductionForm_Load(object sender, EventArgs e)
{
loadSaveIntroduction();
MessageBox.Show(LanguageResources.FormStart);
}
/// <summary>
/// 將自我介紹的資訊顯示到畫面上
/// </summary>
private void loadSaveIntroduction()
{
string dirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data");
string filePath = Path.Combine(dirPath, "Introduction.json");
string imagePath = Path.Combine(dirPath, "Photo.jpeg");
// 每次讀寫檔之前,檢查路徑的資料夾與檔案是否存在,避免發生路徑不存在的錯誤
if (!Directory.Exists(dirPath) || !File.Exists(filePath) || !File.Exists(imagePath))
{
return;
}
// 從JSON檔讀取先前保存的個人資訊
string introductionJsonStr = File.ReadAllText(filePath);
JObject introductionJson = (JObject)JsonConvert.DeserializeObject(introductionJsonStr);
//讀完資料發現資料空白、結構有缺漏、結構被破壞,不要讀取
if (introductionJson == null ||
!introductionJson.ContainsKey("Name") || !introductionJson.ContainsKey("HomeTown") || !introductionJson.ContainsKey("BirthDate"))
{
return;
}
else
{
nameTextBox.Text = introductionJson["Name"].ToString();
homeTownTextBox.Text = introductionJson["HomeTown"].ToString();
birthdate_YearBox.Text = introductionJson["BirthDate"].ToString().Split('-')[0];
birthdate_MonthBox.Text = introductionJson["BirthDate"].ToString().Split('-')[1];
birthdate_DayBox.Text = introductionJson["BirthDate"].ToString().Split('-')[2];
}
photoBox.Image = Image.FromFile(imagePath);
}
/// <summary>
/// 按下「保存個人資訊」
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void saveBtn_Click(object sender, EventArgs e)
{
// 校驗每個欄位是否輸入
TextBox[] allTextBox = new TextBox[] { nameTextBox, homeTownTextBox, birthdate_YearBox, birthdate_MonthBox, birthdate_DayBox };
string[] allTextBoxName = new string[]{LanguageResources.Name, LanguageResources.HomeTown,
LanguageResources.Birthday_Year, LanguageResources.Birthday_Month, LanguageResources.Birthday_Day };
StringBuilder errorMsg = new StringBuilder();
for (int i = 0; i < allTextBox.GetLength(0); i++)
{
if (string.IsNullOrEmpty(allTextBox[i].Text))
{
errorMsg.AppendLine(string.Format(LanguageResources.Message_PleaseInput, allTextBoxName[i]));
}
}
if (errorMsg.ToString() != "")
{
MessageBox.Show(errorMsg.ToString(), "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 校驗日期格式是否正確
if (!Regex.IsMatch(birthdate_YearBox.Text, @"\d") || !Regex.IsMatch(birthdate_MonthBox.Text, @"\d") || !Regex.IsMatch(birthdate_DayBox.Text, @"\d"))
{
MessageBox.Show(LanguageResources.Message_BirthdayNeedNum, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 檢查有沒有選擇大頭照
if (photoBox.Image == null)
{
MessageBox.Show(LanguageResources.Message_NoImage, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string name = nameTextBox.Text;
string homeTown = homeTownTextBox.Text;
int birthDate_Year = int.Parse(birthdate_YearBox.Text);
int birthDate_Month = int.Parse(birthdate_MonthBox.Text);
int birthDate_Day = int.Parse(birthdate_DayBox.Text);
JObject introductionJson = new JObject();
introductionJson.Add("Name", name);
introductionJson.Add("HomeTown", homeTown);
introductionJson.Add("BirthDate", string.Format("{0}-{1}-{2}", birthDate_Year, birthDate_Month, birthDate_Day));
string dirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data");
string jsonPath = Path.Combine(dirPath, "Introduction.json");
string imagePath = Path.Combine(dirPath, "Photo.jpeg");
// 每次讀寫檔之前,檢查路徑的資料夾與檔案是否存在,避免發生路徑不存在的錯誤
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
// 檔案不存在,產生個人資訊的檔案
if (!File.Exists(jsonPath))
{
File.Create(jsonPath).Close();
}
// 保存個人資訊到JSON
File.WriteAllText(jsonPath, JsonConvert.SerializeObject(introductionJson));
// 保存個人大頭貼到Jpeg 圖片
photoBox.Image.Save(imagePath, ImageFormat.Jpeg);
MessageBox.Show("保存完成!", "訊息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// 選擇相片
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void photoBox_DoubleClick(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";
if (fileDialog.ShowDialog() == DialogResult.OK && fileDialog.FileName != "")
{
photoBox.Image = Image.FromFile(fileDialog.FileName);
}
}
/// <summary>
/// 自我介紹按鈕滑鼠偵聽事件:處理按下自我介紹按鈕後要做的事情
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void showIntroductionBtn_Click(object sender, EventArgs e)
{
// 校驗每個欄位是否輸入
TextBox[] allTextBox = new TextBox[] { nameTextBox, homeTownTextBox, birthdate_YearBox, birthdate_MonthBox, birthdate_DayBox };
string[] allTextBoxName = new string[]{LanguageResources.Name, LanguageResources.HomeTown,
LanguageResources.Birthday_Year, LanguageResources.Birthday_Month, LanguageResources.Birthday_Day };
StringBuilder errorMsg = new StringBuilder();
for (int i = 0; i < allTextBox.GetLength(0); i++)
{
if (string.IsNullOrEmpty(allTextBox[i].Text))
{
errorMsg.AppendLine(string.Format(LanguageResources.Message_PleaseInput, allTextBoxName[i]));
}
}
if (errorMsg.ToString() != "")
{
MessageBox.Show(errorMsg.ToString());
return;
}
// 校驗日期格式是否正確
if (!Regex.IsMatch(birthdate_YearBox.Text, @"\d") || !Regex.IsMatch(birthdate_MonthBox.Text, @"\d") || !Regex.IsMatch(birthdate_DayBox.Text, @"\d"))
{
MessageBox.Show(LanguageResources.Message_BirthdayNeedNum);
return;
}
// 取得使用者輸入的姓名和家鄉
string name = nameTextBox.Text;
string homeTown = homeTownTextBox.Text;
// 取得當下的日期
int today_Year = DateTime.Today.Year;
int today_Month = DateTime.Today.Month;
int today_Day = DateTime.Today.Day;
int yearOld;
// 計算年齡
int birthDate_Year = int.Parse(birthdate_YearBox.Text);
int birthDate_Month = int.Parse(birthdate_MonthBox.Text);
int birthDate_Day = int.Parse(birthdate_DayBox.Text);
yearOld = today_Year - int.Parse(birthdate_YearBox.Text);
if (today_Month < birthDate_Month || (today_Month == birthDate_Month && today_Day < birthDate_Day))
{
yearOld = yearOld - 1;
}
// 顯示自我介紹
string introductionText = string.Format(LanguageResources.Message_IntrouductionText, name, homeTown, yearOld);
MessageBox.Show(introductionText);
}
/// <summary>
/// 自訂函式:判斷是否為整數
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
private bool stringIsInt(string num)
{
int tryParse;
return int.TryParse(num, out tryParse);
}
/// <summary>
/// 生日欄位的鍵盤偵聽事件,讓使用者只能輸入數字
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void birthdate_YearBox_KeyPress(object sender, KeyPressEventArgs e)
{
char inputChar = e.KeyChar;
e.Handled = ! (char.IsDigit(inputChar) || char.IsControl(e.KeyChar));
}
}
}
讀寫檔看似是一個簡單的輸入輸出流程,往往需要考量到檔案和型態在使用者的操作過程,可能因為什麼狀況而造成程式錯誤。建議自己在不看程式碼的情況下練習讀寫檔的功能,對於型態和檔案讀寫的經驗和能力也會幫助許多。
自我介紹的程式功能大致完成了,但是你從程式結構面的角度會發現,程式碼全部混在同一個檔案,也有許多重複的地方。明天為我們的程式碼結構進行整理,準備為第一支自我介紹程式畫下句點。